package wator.util;

import java.util.HashMap;
import java.util.Vector;

import wator.model.Agent;
import wator.model.AgentConfiguration;
import wator.model.AvailableAgents;
import wator.model.agents.BigFishAgent;
import wator.model.agents.EnergySharkAgent;
import wator.model.agents.FishAgent;
import wator.model.agents.SharkAgent;
import wator.model.agents.SmallFishAgent;
import wator.model.strategies.InertiaRandomMovementStrategy;
import wator.model.strategies.RandomMovementStrategy;
import wator.model.strategies.WeightedForceVectorStrategy;

public class BatchSimulationConfiguration {
	
	public String predator="";
	public String prey="";
	
	public int numberOfRounds=1000;
	public int numberOfSimulations=10;
	
	public int starvePredatorFrom=10;
	public int starvePredatorTo=20;
	public int starvePredatorStep=1;
	
	public int breedPredatorFrom=10;
	public int breedPredatorTo=20;
	public int breedPredatorStep=1;
	
	public int breedPreyFrom=10;
	public int breedPreyTo=20;
	public int breedPreyStep=1;
	
	private Vector<String> selectedSpecies=new Vector<String>();
	private HashMap<String, SpecieConf> speciesConf=new HashMap<String,SpecieConf>();
	
	private String[] availableSpecies=new String[]	{"SharkAgent",
													"EnergySharkAgent",
													"FishAgent",
													"SmallFishAgent",
													"BigFishAgent"};
	
	public BatchSimulationConfiguration()
	{
		for(String spec : availableSpecies)
			speciesConf.put(spec, new SpecieConf(spec));
		
	}
	
	public void selectPredator(String name)
	{
		if(speciesConf.containsKey(name))
		{
			if(predator.equals(""))
			{
				if(name.contains("Shark"))
				{
					addSpecie(name);
					predator=name;
				}else System.out.println("The specie `"+name+"` is not a predator!");
			}else System.out.println("The predator was already selected!");
		}
		else
			System.out.println("The specie `"+name+"` does not exist!");
	}
	public void selectPrey(String name)
	{
		if(speciesConf.containsKey(name))
		{
			if(prey.equals(""))
			{
				if(!name.contains("Shark"))
				{
					addSpecie(name);
					prey=name;
				}else System.out.println("The specie `"+name+"` is not a predator!");
			}else System.out.println("The prey was already selected!");
		}
		else
			System.out.println("The specie `"+name+"` does not exist!");
	}
	private void addSpecie(String name)
	{
		if(this.selectedSpecies.size()<2)
		{
			if(speciesConf.containsKey(name))
			{
				if(selectedSpecies.contains(name))
					System.out.println("The specie `"+name+"` was already added");
				else{
					this.selectedSpecies.add(name);
					if(selectedSpecies.size()==2)
					{
						AgentConfiguration[] confs= AvailableAgents.getInstance().getConfigurations();
						for(AgentConfiguration conf : confs)
						{
							String agentType=Tools.extractAgentType(conf.getTemplate().toString());
							if(!selectedSpecies.contains(agentType))
								conf.setInitialPopulationSize(0);
							else
								conf.setEnabled(true);
						}
					}
				}
			}
			else
				System.out.println("The specie `"+name+"` does not exist!");
		}else
			System.out.println("You cannot select more than 2 species for a batch simulation");
	}
	
	public void setParameter(String specie,String key,String value)
	{
		if(selectedSpecies.contains(specie))
		{
			SpecieConf conf=speciesConf.get(specie);//.setParameter(key, value);
			conf.setParameter(key, value);
			speciesConf.put(specie,conf);
		}
		else System.out.println("The specie `"+specie+"` was not selected !");
	}
	public void setBatchIntervals(	int starvePredatorFrom,int starvePredatorTo, 
									int breedPreyFrom, int breedPreyTo,
									int breedPredatorFrom,int breedPredatorTo)
	{
		this.starvePredatorFrom=starvePredatorFrom;
		this.starvePredatorTo=starvePredatorTo;
		this.breedPredatorFrom=breedPredatorFrom;
		this.breedPredatorTo=breedPredatorTo;
		this.breedPreyFrom=breedPreyFrom;
		this.breedPreyTo=breedPreyTo;
		
	}
	public void setBatchSteps(int starvePredatorStep,int breedPreyStep,int breedPredatorStep)
	{
		this.starvePredatorStep=starvePredatorStep;
		this.breedPreyStep=breedPreyStep;
		this.breedPredatorStep=breedPredatorStep;
	}
	public void setNumberOfSimulations(int num)
	{
		numberOfSimulations=num;
	}
	public void setNumberOfRounds(int num)
	{
		numberOfRounds=num;
	}
	public void updateSimulationParameters(int starvePredator,int breedPrey,int breedPredator)
	{
		speciesConf.get(predator).setParameter("starve",""+starvePredator);
		speciesConf.get(predator).setParameter("breed",""+breedPredator);
		speciesConf.get(prey).setParameter("breed",""+breedPrey);
	}
	
	public boolean isSelected(String agentType) {
		return selectedSpecies.contains(agentType);
	}
	
	private class SpecieConf
	{
		
		private String specie;
		private Agent tmp_agent;
		
		public SpecieConf(String specie)
		{	
			this.specie=new String(specie);
			if(specie.equals("SharkAgent"))
				tmp_agent=new SharkAgent(null);
			if(specie.equals("EnergySharkAgent"))
				tmp_agent=new EnergySharkAgent(null);
			if(specie.equals("FishAgent"))
				tmp_agent=new FishAgent(null);
			if(specie.equals("SmallFishAgent"))
				tmp_agent=new SmallFishAgent(null);
			if(specie.equals("BigFishAgent"))
				tmp_agent=new BigFishAgent(null);
		}
		
		public void setParameter(String key,String value)
		{
			if(key.equals("breed"))
				tmp_agent.setSpeciesParameter("Breed Time",new Integer(value));
			else if(key.equals("starve"))
				tmp_agent.setSpeciesParameter("Starve Time",new Integer(value));
			else if (key.equals("population"))
			{
				AgentConfiguration[] confs= AvailableAgents.getInstance().getConfigurations();
				for(AgentConfiguration conf : confs)
				{
					String agentType=Tools.extractAgentType(conf.getTemplate().toString());
					if(agentType.equals(this.specie))
						conf.setInitialPopulationSize(new Integer(value));	
				}
			}	
			else if(key.equals("strategy") || key.equals("str"))
			{
				String str=(String)value;
				Vector<Integer> parameters=new Vector<Integer>();
				String strategy=Tools.parseStrategy(parameters,str);
				
				try{
					if(strategy.equals("NoMovement")) 
					{
						if(parameters.size()!=0) throw new ParameterError(strategy,0);
					}
					else if(strategy.equals("Random"))
					{
						if(parameters.size()!=1) throw new ParameterError(strategy+"(Reach)",1);
						RandomMovementStrategy strat=new RandomMovementStrategy();	
						strat.setParameter("Reach", new Integer(parameters.get(0)));
						tmp_agent.setMovementStrategy(strat);
					}
					else if(strategy.equals("InertiaRandom"))
					{
						if(parameters.size()!=3) throw new ParameterError(strategy+"(onSpeed,Inertia Weight,Max. Velocity)",3);
						InertiaRandomMovementStrategy strat;
						if(parameters.get(0).equals("1"))
							strat=new InertiaRandomMovementStrategy(true);
						else
							strat=new InertiaRandomMovementStrategy(false);
						strat.setParameter("Inertia Weight", new Integer(parameters.get(1)));
						strat.setParameter("Max. Velocity", new Integer(parameters.get(2)));
						tmp_agent.setMovementStrategy(strat);
					}
					else if(strategy.equals("WeightedForceVector"))
					{
						if(parameters.size()!=8) throw new ParameterError(strategy+"(onSpeed,Flocking,Predator Avoid.,Prey Attraction,Energy Attraction,Separation Range,Inertia,Max. Velocity)",8);
						WeightedForceVectorStrategy strat;
						if(parameters.get(0).equals("1"))
							strat=new WeightedForceVectorStrategy(true);
						else
							strat=new WeightedForceVectorStrategy(false);
						
						strat.setParameter("Flocking", new Integer(parameters.get(1)));
						strat.setParameter("Predator Avoid.", new Integer(parameters.get(2)));
						strat.setParameter("Prey Attraction", new Integer(parameters.get(3)));
						strat.setParameter("Energy Attraction", new Integer(parameters.get(4)));
						strat.setParameter("Separation Range", new Integer(parameters.get(5)));
						strat.setParameter("Inertia", new Integer(parameters.get(6)));
						strat.setParameter("Max. Velocity", new Integer(parameters.get(7)));
					
						tmp_agent.setMovementStrategy(strat);

					}
					else
						System.out.println("The strategy `"+strategy+"` does not exist");

				}
				catch(ParameterError e)
				{
					System.out.println("Wrong number of arguments for strategy `"+e.strategy+"`. Expected "+e.argc+".");
				}
				
			}
			else 
				System.out.println("The parameter `"+key+"` does not exist !");
		}
		
		private class ParameterError extends Exception
		{
			public String strategy;
			public int argc;
			
			public ParameterError(String strategy,int argc) {
				this.strategy=new String(strategy);
				this.argc=argc;
			}
		}
	}

	

}
